package com.uuah.server.config.spring.parsers.processors;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.config.BeanDefinition;

import com.uuah.server.config.spring.parsers.PostProcessor;
import com.uuah.server.config.spring.parsers.assembly.IBeanAssembler;
import com.uuah.server.config.spring.parsers.assembly.IBeanAssemblerFactory;
import com.uuah.server.config.spring.parsers.assembly.configuration.IPropertyConfiguration;

/**
 * This iterates over child elements, parsing them and calling
 * {@link #insertBean(com.uuah.server.config.spring.parsers.assembly.IBeanAssembler, org.springframework.beans.factory.config.BeanDefinition, org.w3c.dom.Element, org.w3c.dom.Element)}
 * .
 *
 * <p>
 * There are two ways we can parse a tree of elements - have an external loop or
 * let each parser iterate over its own children. Uuah App Server uses the first strategy,
 * but some (most? all?) third party BDPs use the second. This processor lets us
 * use third party beans inside the Uuah App Server framework.
 *
 * <p>
 * So this is a very specialised parser that should only be used when trying to
 * inter-operate with beans from third party packages which themselves control
 * how their children are parsed.
 *
 * <p>
 * Since for Uuah App Server beans the iteration over child elements (at least currently)
 * is done via
 * {@link com.uuah.server.config.spring.UuahHierarchicalBeanDefinitionParserDelegate} the
 * calling parser needs to set the flag
 * {@link com.uuah.server.config.spring.UuahHierarchicalBeanDefinitionParserDelegate#UUAH_NO_RECURSE}
 * - this stops the Uuah App Server recursion from working.
 *
 * <p>
 * NOTE - IMHO (ac) the Uuah App Server approach was probably a mistake; this processor
 * could be used as a way to slowly migrate the Uuah App Server code to the more common
 * approach.
 */
public abstract class AbstractChildElementIterator implements PostProcessor {

	private IBeanAssemblerFactory beanAssemblerFactory;
	private IPropertyConfiguration configuration;

	public AbstractChildElementIterator(
			IBeanAssemblerFactory beanAssemblerFactory,
			IPropertyConfiguration configuration) {
		this.beanAssemblerFactory = beanAssemblerFactory;
		this.configuration = configuration;
	}

	public void postProcess(ParserContext context, IBeanAssembler assembler,
			Element element) {
		NodeList children = element.getChildNodes();
		for (int i = 0; i < children.getLength(); ++i) {
			Node child = children.item(i);
			if (child.getNodeType() == Node.ELEMENT_NODE) {
				processChildElement(context, assembler, element,
						(Element) child);
			}
		}
	}

	protected void processChildElement(ParserContext context,
			IBeanAssembler assembler, Element parent, Element child) {
		BeanDefinition childBean = context.getDelegate().parseCustomElement(
				child, assembler.getBean().getBeanDefinition());
		IBeanAssembler targetAssembler = beanAssemblerFactory.newBeanAssembler(
				null, null, configuration, assembler.getBean()
						.getRawBeanDefinition());
		insertBean(targetAssembler, childBean, parent, child);
	}

	protected abstract void insertBean(IBeanAssembler targetAssembler,
			BeanDefinition childBean, Element parent, Element child);

}
